<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>5-12 高斯模糊</title>
</head>

<body>
  <canvas id="c" width="700" height="300" style="border: 1px solid #ccc;"></canvas>

  <script>
    const context = document.getElementById('c')
    const ctx = context.getContext('2d')

    const img = new Image()
    img.src = '../images/desert.jpg'

    img.onload = () => {
      ctx.drawImage(img, 10, 10)

      const imgData = ctx.getImageData(10, 10, 300, 200)

      const data = imgData.data
      const width = imgData.width
      const height = imgData.height

      const gaussMatrix = []

      let gaussSum = 0
      let x = 0
      let y = 0

      let i = 0
      let j = 0
      let k = 0
      let len = 0

      const radius = 10
      const sigma = 5

      let r = 0
      let g = 0
      let b = -1 / (2 * sigma * sigma)
      let a = 1 / (Math.sqrt(2 * Math.PI) * sigma)

      // 生成高斯矩阵
      for (i = 0, x = -radius; x <= radius; x++, i++) {
        g = a * Math.exp(b * x * x)
        gaussMatrix[i] = g
        gaussSum += g
      }

      // 归一化, 保证高斯矩阵的值在[0,1]之间
      for (i = 0, len = gaussMatrix.length; i < len; i++) {
        gaussMatrix[i] /= gaussSum
      }

      // x 方向一维高斯运算
      for (y = 0; y < height; y++) {
        for (x = 0; x < width; x++) {
          r = g = b = a = 0
          gaussSum = 0
          for (j = -radius; j <= radius; j++) {
            k = x + j
            if (k >= 0 && k < width) { // 确保 k 没超出 x 的范围
              // r,g,b,a 四个一组
              i = (y * width + k) * 4
              r += data[i] * gaussMatrix[j + radius]
              g += data[i + 1] * gaussMatrix[j + radius]
              b += data[i + 2] * gaussMatrix[j + radius]
              gaussSum += gaussMatrix[j + radius]
            }
          }
          i = (y * width + x) * 4
          // 除以 gaussSum 是为了消除处于边缘的像素, 高斯运算不足的问题
          // console.log(gaussSum)
          data[i] = r / gaussSum
          data[i + 1] = g / gaussSum
          data[i + 2] = b / gaussSum
        }
      }

      // y 方向一维高斯运算
      for (x = 0; x < width; x++) {
        for (y = 0; y < height; y++) {
          r = g = b = a = 0
          gaussSum = 0
          for (j = -radius; j <= radius; j++) {
            k = y + j
            if (k >= 0 && k < height) { // 确保 k 没超出 y 的范围
              i = (k * width + x) * 4
              r += data[i] * gaussMatrix[j + radius]
              g += data[i + 1] * gaussMatrix[j + radius]
              b += data[i + 2] * gaussMatrix[j + radius]
              gaussSum += gaussMatrix[j + radius]
            }
          }
          i = (y * width + x) * 4
          data[i] = r / gaussSum
          data[i + 1] = g / gaussSum
          data[i + 2] = b / gaussSum
        }
      }

      ctx.putImageData(imgData, 340, 10)
    }
  </script>
</body>

</html>